package com.liry.security.util;

import java.io.InputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

/**
 * rsa加密工具简化版
 *
 * @author ALI
 * @date 2021-09-25 15:44
 */
public class RsaUtil {

    private static final String RSA_ALGORITHM = "RSA";
    private static final String AES_ALGORITHM = "AES";

    private RsaUtil() {
    }

    /**
     * 生成密钥对
     *
     * @param passKey 关键密码
     * @return 密钥对
     */
    public static KeyPair genratorKeyPair(String passKey) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        SecureRandom secureRandom = new SecureRandom(passKey.getBytes());
        secureRandom.setSeed(passKey.getBytes());
        keyPairGenerator.initialize(2048, secureRandom);
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 加密密码
     *
     * @param password  密码
     * @param publicKey 公钥
     * @return 加密后的密文
     */
    public static byte[] encrypt(PublicKey publicKey, byte[] password) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(password);
        } catch (Exception e) {
            throw new RuntimeException("RSA加密失败（RSA encrypt failed.）");
        }
    }

    /**
     * 解密密码
     *
     * @param encryptPassword 加密的密码
     * @param privateKey      私钥
     * @return 解密后的明文
     */
    public static byte[] decrypt(PrivateKey privateKey, byte[] encryptPassword) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return cipher.doFinal(encryptPassword);
        } catch (Exception e) {
            throw new RuntimeException("RSA解密失败（RSA encrypt failed.）");
        }
    }

    /**
     * 密钥Base64
     *
     * @param privateKey 密钥
     * @return 结果
     */
    public static String getPrivateBase64(PrivateKey privateKey) {
        return Base64.getEncoder().encodeToString(privateKey.getEncoded());
    }

    /**
     * 公钥Base64
     *
     * @param publicKey 公钥
     * @return 结果
     */
    public static String getPublicBase64(PublicKey publicKey) {
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }

    /**
     * 根据公钥字符串获取公钥对象
     *
     * @param publicKeyString 公钥字符串
     * @return 结果
     */
    public static PublicKey getPublicKey(String publicKeyString)
    throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decode = Base64.getDecoder().decode(publicKeyString);
        return KeyFactory.getInstance(RSA_ALGORITHM).generatePublic(new X509EncodedKeySpec(decode));
    }

    /**
     * 根据密钥字符串获取密钥对象
     *
     * @param privateKeyString 密钥字符串
     * @return 结果
     */
    public static PrivateKey getPrivateKey(String privateKeyString)
    throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decode = Base64.getDecoder().decode(privateKeyString);
        return KeyFactory.getInstance(RSA_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decode));
    }

    /**
     * 对称加密AES 对称key生成
     *
     * @param passKey 关键密码
     * @return 生成aes的key
     * @throws NoSuchAlgorithmException 算法找不到异常
     */
    public static SecretKey aesKey(String passKey) throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.setSeed(passKey.getBytes());
        keyGenerator.init(secureRandom);
        return keyGenerator.generateKey();
    }

    /**
     * @param mode      加解密模式：Cipher.ENCRYPT_MODE / Cipher.DECRYPT_MODE
     * @param secretKey 对称key
     * @param password  执行的密码
     */
    public static byte[] aes(int mode, SecretKey secretKey, byte[] password) {
        try {
            Cipher instance = Cipher.getInstance(AES_ALGORITHM);
            instance.init(mode, secretKey);
            return instance.doFinal(password);
        } catch (Exception e) {
            throw new RuntimeException(String.format("AES执行失败,Cipher.mode:%s（AES encrypt failed.）", mode));
        }
    }

    public static void main(String[] args) throws Exception {

        String passkey = "dd";
        KeyPair dd = genratorKeyPair(passkey);
        String pu = new String(Base64.getEncoder().encode(dd.getPublic().getEncoded()));
        String en = new String(Base64.getEncoder().encode(dd.getPrivate().getEncoded()));
        System.out.println("publicKey:\n" + pu);
        System.out.println("private:\n" + en);

        // 加解密方案1：RSA + AES双重加密
        // 1. AES加密
        SecretKey key = aesKey(passkey);
        byte[] aesEn = aes(Cipher.ENCRYPT_MODE, key, "123456".getBytes());
        // 2. 通过RSA公钥加密密码
        byte[] rsaEn = encrypt(dd.getPublic(), aesEn);
        // 3. 通过RSA私钥解密密码
        byte[] rsaDe = decrypt(dd.getPrivate(), rsaEn);
        // 4. 再同AES解密
        byte[] aesDe = aes(Cipher.DECRYPT_MODE, key, rsaDe);
        System.out.println("两重解密：" + new String(aesDe));

        // 加解密方案2：RSA加密
        byte[] encrypt = encrypt(RsaUtil.getPublicKey(pu), "123456".getBytes());
        byte[] decrypt = decrypt(RsaUtil.getPrivateKey(en), encrypt);
        System.out.println("RSA解密：" + new String(decrypt));
    }
}